home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 May: Tool Chest / Dev.CD May 98 TC.toast / Tool Chest / Development Kits / HyperCard Related / APDA HyperCard Toolkits / HyperCard Serial Toolkit 2.6 / Source Code / recvUpTo.p < prev    next >
Encoding:
Text File  |  1995-02-07  |  8.1 KB  |  273 lines  |  [TEXT/MPS ]

  1. (*
  2.     recvUpTo(termination character, waitTime,oldString) -- Return a string from the
  3.         serial port; return everything available, up to the termination character (if any). Pass an empty
  4.         termination character to receive everything available. WaitTime is the amount of time to wait
  5.         for the input, in ticks (60ths of a second). oldString is what was read the last call (presumably
  6.         terminated due to a time-out).
  7.  
  8.     To compile and link this file using Macintosh Programmer's Workshop,
  9.  
  10.         pascal -w recvUpTo.p
  11.         link -m ENTRYPOINT -o HyperCommands -rt XFCN=7032 -sn Main=recvUpTo ∂
  12.             recvUpTo.p.o "{MPW}"Libraries:interface.o "{MPW}"Libraries:Libraries:HyperXLib.o
  13.  
  14.     © Copyright 1987,88,89 by Apple Computer, Inc.
  15.  
  16.     Initial coding 9/87 by Harry R. Chesley.
  17. *)
  18.  
  19. {$R-}
  20.  
  21. {$S recvUpTo }     { Segment name must be the same as the command name. }
  22.  
  23. unit DummyUnit;
  24.  
  25. interface
  26.  
  27. uses MemTypes, QuickDraw, OSIntf, ToolIntf, HyperXCmd;
  28.  
  29. procedure EntryPoint(paramPtr: XCmdPtr);
  30.     
  31. implementation
  32.  
  33. const
  34.  
  35. return = 13;                { Carriage return. }
  36. linefeed = 10;            { Line feed. }
  37. bs = 8;                        { Back space. }
  38. delete = 127;            { Delete. }
  39. space = ord(' ');        { Space. }
  40. tab = 9;                    { Horizontal tab. }
  41.  
  42. procedure recvUpTo(paramPtr: XCmdPtr); forward;
  43.  
  44. procedure EntryPoint(paramPtr: XCmdPtr);
  45.  
  46.     begin
  47.         recvUpTo(paramPtr);
  48.     end;
  49.  
  50. procedure recvUpTo(paramPtr: XCmdPtr);
  51.  
  52.     var str: Str255;
  53.         l: longInt;
  54.         waitForChars: longInt;        { Ticks to wait until for characters (compated to TickCount). }
  55.         lookForTerm: boolean;        { True if we're looking for a terminator character. }
  56.         termChar: signedByte;        { The terminator character we're looking for. }
  57.         resultHand: Handle;            { A handle to the result string. }
  58.         resultSize: longInt;            { The size of the result string (minus the zero termination tacked on last). }
  59.         theChar: signedByte;
  60.         p, p2: Ptr;
  61.         col: integer;                        { The current column. }
  62.         i,j: integer;
  63.  
  64.     procedure Fail(errMsg: Str255); { set theResult and quit }
  65.         begin
  66.             paramPtr^.returnValue := PasToZero(paramPtr,errMsg);
  67.             exit(recvUpTo);
  68.         end;
  69.  
  70.     {$I SPortUtil.inc}
  71.  
  72.     procedure sendByte(b: SignedByte);
  73.         { Send one byte out the port. }
  74.  
  75.         var l: longInt;
  76.  
  77.         begin
  78.             l := 1;
  79.             if FSWrite(ThisSPort.portOutDev,l,@b) <> noErr then Fail('FSWrite failed');
  80.         end;
  81.  
  82.     procedure sendCRLF;
  83.         { Send a carriage return/linefeed out the port. }
  84.  
  85.         begin
  86.             sendByte(return); sendByte(linefeed);
  87.         end;
  88.  
  89.     procedure sendBS;
  90.         { Backspace on a terminal attached to the port: backspace, then space to erase any character in the
  91.             previous position, then backspace again to get the cursor in the right place. }
  92.  
  93.         begin
  94.             sendByte(bs); sendByte(space); sendByte(bs);
  95.         end;
  96.  
  97.     procedure disposAndFail(err: str255);
  98.         { Fail routine used after the result handle has been allocated. }
  99.  
  100.         begin
  101.             DisposHandle(resultHand);
  102.             Fail(err);
  103.         end;
  104.  
  105.     begin
  106.         if paramPtr^.paramCount <> 3 then Fail('parameter count is not 3');
  107.  
  108.         SetUpSPortGlobals;
  109.         EnsureOpenPort;
  110.  
  111.         GetStrParm(1,str);                                        { First parameter is termination character. }
  112.         if length(str) = 0 then lookForTerm := false
  113.         else
  114.             begin
  115.                 lookForTerm := true;
  116.                 termChar := SignedByte(str[1]);
  117.             end;
  118.         waitForChars := GetLongParm(2);                    { Second parameter is whether to wait. }
  119.         resultHand := paramPtr^.params[3];                { Third parameter is the old string. }
  120.  
  121.         { If there's anything in the "previous" string, copy it. }
  122.         if resultHand <> NIL then
  123.             begin
  124.                 p := resultHand^;
  125.                 resultSize := 0;
  126.                 while p^ <> 0 do
  127.                     begin
  128.                         resultSize := resultSize + 1;
  129.                         p := Ptr(ord4(p)+1);
  130.                     end;
  131.                 if resultSize < 0 then Fail('Input string size too small!');
  132.                 if HandToHand(resultHand) <> noErr then Fail('HandToHand failed!');
  133.                 SetHandleSize(resultHand,resultSize);
  134.             end
  135.         { On the other hand, if the previous string is empty, make a new, empty one. }
  136.         else
  137.             begin
  138.                 resultHand := NewHandle(0);
  139.                 resultSize := 0;
  140.             end;
  141.  
  142.         { Get our current idea of where the other side's cursor is. }
  143.         col := ThisSPort.currentColumn;
  144.  
  145.         { Figure out when to stop trying (timeout). }
  146.         waitForChars := waitForChars + TickCount;
  147.  
  148.         { Cycle until the timeout happens or we see the termintor character. }
  149.         while true do
  150.             begin
  151.                 { Check if there's any input from the port. }
  152.                 if SerGetBuf(ThisSPort.portInDev,l) <> noErr then disposAndFail('SerGetBuf failed');
  153.                 { If not, do another round or get out, depending on the timeout condition. }
  154.                 if l = 0 then
  155.                     begin
  156.                         if TickCount > waitForChars then leave
  157.                         else cycle;
  158.                     end;
  159.  
  160.                 { Expand the result handle and read in the first character that's waiting. }
  161.                 resultSize := resultSize+1;
  162.                 SetHandleSize(resultHand,resultSize);
  163.                 if MemError <> noErr then disposAndFail('SetHandleSize failed!');
  164.                 HLock(resultHand);
  165.                 l := 1;
  166.                 if FSRead(ThisSPort.portInDev,l,Ptr(ord4(resultHand^)+resultSize-1)) <> noErr then
  167.                     disposAndFail('FSRead failed');
  168.                 HUnlock(resultHand);
  169.  
  170.                 { Strip the character, if appropriate, and then get it into theChar. }
  171.                 p := Ptr(ord4(resultHand^)+resultSize-1);
  172.                 if ThisSPort.stripIncoming then p^ := BAND(p^,$7F);
  173.                 theChar := p^;
  174.  
  175.                 { Weed out control characters, if appropriate. }
  176.                 if ThisSPort.stripControls then
  177.                     if (theChar < space) and (theChar <> tab) and (theChar <> return) and (theChar <> bs) then
  178.                         begin
  179.                             resultSize := resultSize-1;
  180.                             SetHandleSize(resultHand,resultSize);
  181.                             cycle;
  182.                         end;
  183.  
  184.                 { If we're echoing... }
  185.                 if ThisSPort.doEcho then
  186.                     begin
  187.                         { If this is a backspace... }
  188.                         if ThisSPort.doEdit and ((theChar = bs) or (theChar = delete)) then
  189.                             begin
  190.                                 if (col > 1) and (resultSize > 1) then
  191.                                     begin
  192.                                         sendBS;
  193.                                         col := col-1;
  194.                                     end;
  195.                             end
  196.                         { If it's a carriage return... }
  197.                         else if theChar = return then
  198.                             begin
  199.                                 sendCRLF;
  200.                                 col := 1;
  201.                             end
  202.                         { If it's a normal, non-wrapped character... }
  203.                         else if (col < WRAPCOLUMN) or (not ThisSPort.autoWrap) then
  204.                             begin
  205.                                 sendByte(theChar);
  206.                                 col := col+1;
  207.                             end
  208.                         { If it's a space in the wrap column (which only allows spaces)... }
  209.                         else if (theChar = space) and (col = WRAPCOLUMN) then
  210.                             begin
  211.                                 sendByte(space);
  212.                                 col := col+1;
  213.                             end
  214.                         { Otherwise, wrap the last word of the line onto the next line... }
  215.                         else
  216.                             begin
  217.                                 { Figure out how many characters will wrap... }
  218.                                 p := pointer(ord4(resultHand^)+resultSize);
  219.                                 i := 0;
  220.                                 while p <> resultHand^ do
  221.                                     begin
  222.                                         p := pointer(ord4(p)-1);
  223.                                         if (p^ = space) or (p^ = return) then leave;
  224.                                         i := i+1;
  225.                                     end;
  226.                                 { If it's the entire line, forget it. }
  227.                                 if i >= MAXWRAP then i := 1;
  228.                                 { If there's nothing to wrap, then just send a carriage return/linefeed. }
  229.                                 if i = 0 then i := 1
  230.                                 { Otherwise, backspace thru the characters being wrapped, then go to the next
  231.                                     line, then send the wrapping characters. }
  232.                                 else
  233.                                     begin
  234.                                         if i > 1 then for j := 1 to i-1 do sendBS;
  235.                                         sendCRLF;
  236.                                         for j := resultSize-i to resultSize-1 do
  237.                                             sendByte(Ptr(ord4(resultHand^)+j)^);
  238.                                     end;
  239.                                 col := i+1;
  240.                             end;
  241.                     end;
  242.  
  243.                 { If we're editing this line and this is the edit character... }
  244.                 if ThisSPort.doEdit and (theChar = bs) or (theChar = delete) then
  245.                     begin
  246.                         { Eliminate the backspace character. }
  247.                         resultSize := resultSize-1;
  248.                         { If we're allowed to edit it (i.e., it isn't on the previous line on the screen),
  249.                             eliminate the erased character. }
  250.                         if (col >= 1) or (not ThisSPort.doEcho) then resultSize := resultSize-1;
  251.                         { Make sure we're not deleting more than there is. }
  252.                         if resultSize < 0 then resultSize := 0;
  253.                         { Delete it. }
  254.                         SetHandleSize(resultHand,resultSize);
  255.                     end;
  256.                 if lookForTerm and (theChar = termChar) then leave;
  257.                 if resultSize > 30000 then leave;
  258.             end;
  259.  
  260.         { Add in the zero termination for the string. }
  261.         SetHandleSize(resultHand,resultSize+1);
  262.         p := ptr(ord4(resultHand^)+resultSize);
  263.         p^ := 0;
  264.  
  265.         { Return the handle. }
  266.         paramPtr^.returnValue := resultHand;
  267.  
  268.         { Remember where we think the cursor column is. }
  269.         Globals^^.ports[Globals^^.selectedPort].currentColumn := col;
  270.     end;
  271.  
  272. end.
  273.